package cn.biplam.back.operator.tree;

import java.util.ArrayList;

import cn.biplam.back.sql.dml.Update;
import cn.biplam.common.client.DataFilter;
import cn.biplam.common.client.DbResource;
import cn.biplam.common.client.Operator;
import cn.biplam.common.client.OperatorResult;
import cn.biplam.common.opcode.SysManageCode.TreeIndexCode;
import cn.biplam.common.paramters.TreeParam;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.sqlresult.SqlResult;
import cn.biplam.common.wrapper.tree.TreeIndexFields;

/**
 * 
 * @author XiaoRuxing Nov 9, 20095:08:09 PM
 * @version 1.0
 */
public class IndexTree {

	protected String tableName;
	protected String userId;
	protected TreeIndexFields fields = null;
	protected static final String TABLE_NAME = "table_name";
	protected DbResource dbResource;

	/** 主题起始排序号 */
	protected static final int Theme_Start_Order = 0;
	/** 非主题(叶子节点)起始排序号 */
	protected static final int Non_Theme_Start_Order = 5000;
	/** 自定义节点起始排序号 */
	protected static final int Custom_Node_Order = 10000;

	protected IndexTree(String userId ,
			String tableName, 
			TreeIndexFields fields,
			DbResource dbResource){
		this.userId = userId;
		this.tableName = tableName;
		this.fields = fields;
		this.dbResource = dbResource;
	}

	/**
	 * 更新节点内容
	 * @param filter 更新节点的内容包括：节点名、节点描述、节点类型
	 */
	protected void update(ArrayList<String> sql,DataFilter filter) throws ErrorMessage{
		/** 生成节点ID */
		String nodeID=TOOLS.changeEmptyToNull(filter.getValue(this.fields.getNodeId()));
		/** 获取节点在物理表中的ID */
		String nodeRelId=TOOLS.changeEmptyToNull(filter.getValue(this.fields.getRealId()));

		Update update=new Update(this.tableName);
		update.putStringFieldIgnoreNull(this.fields.getNodeParent(), filter.getValue(this.fields.getNodeParent()));
		update.putStringFieldIgnoreNull(this.fields.getNodeName(), filter.getValue(this.fields.getNodeName()));
		update.putStringFieldIgnoreNull(this.fields.getNodeDesc(), filter.getValue(this.fields.getNodeDesc()));
		update.putFieldIgnoreNull(this.fields.getNodeSequence(), filter.getValue(this.fields.getNodeSequence()));
		update.putStringFieldIgnoreNull(this.fields.getOperatorType(), filter.getValue(this.fields.getOperatorType()));
		update.putStringFieldIgnoreNull(this.fields.getNodeType(), filter.getValue(this.fields.getNodeType()));

		String where=null;
		if(nodeID!=null){
			update.putStringFieldIgnoreNull(this.fields.getRealId(), filter.getValue(this.fields.getRealId()));
			where=this.fields.getNodeId()+"='"+nodeID+"'";
		}else{
			where=this.fields.getRealId()+"='"+nodeRelId+"'";
		}
		update.setWhere(where);
		sql.add(update.getSimpleSql());
	}

	/**
	 * 将节点的弟弟节点排序向前移动一位<br>
	 * 用于: 节点删除或者移走时<br>
	 * 只移动弟弟节点中指定类型的节点(主题或者叶子节点)<br>
	 * @throws ErrorMessage 
	 */
	protected void forwardSiblingSequence(ArrayList<String> sql,
			String sParentID,String sequence,
			String operatorType) throws ErrorMessage{
		this.moveLBrother(sql, sParentID, sequence, operatorType, false);
	}

	/**
	 * 将节点的弟弟节点排序向后移动一位<br>
	 * 用于: 节点删除或者移走时<br>
	 * 只移动弟弟节点中指定类型的节点(主题或者叶子节点)<br>
	 * @throws ErrorMessage 
	 */
	protected void afterSiblingSequence(ArrayList<String> sql,String sParentID,Object sequence,
			String operatorType) throws ErrorMessage{
		this.moveLBrother(sql, sParentID, sequence, operatorType, true);
	}

	/**
	 * 兄弟节点个数 
	 * @return 
	 * 		   父亲下面的所有儿子的个数<br>
	 *         父亲节点不存在或者父亲节点下无儿子返回0<br>
	 *         (从数据库查询获取)<br>
	 * @throws ErrorMessage 
	 */
	protected int getSiblingNumb(String parentId,
			String nodeType) throws ErrorMessage{
		//获取所有的兄弟
		OperatorResult childs = getSibling(parentId, nodeType, null);
		//获取兄弟个数
		int siblingNumb;
		if(TOOLS.exist(childs)){
			siblingNumb = childs.size();
		}else{
			siblingNumb = 0;
		}
		return siblingNumb;
	}

	/**
	 *  获取指定节点的所有儿子节点
	 *  @param parentId     父亲
	 *  @param nodeType     节点索引(可以为空,模型选择树使用)
	 *  @param operatorType 节点类型
	 * @return 节点下的直接儿子
	 * @throws ErrorMessage 
	 */
	protected OperatorResult getSibling(
			String parentId, 
			String nodeType,
			String operatorType) throws ErrorMessage{
		DataFilter filter = new DataFilter();
		filter.put(TABLE_NAME, this.tableName);
		//父节点ID
		filter.put(this.fields.getNodeId(), parentId);
		//节点索引类型
		filter.put(this.fields.getNodeType(), nodeType);
		//节点类型
		filter.put(this.fields.getOperatorType(), operatorType);
		//获取节点的子节点
		return Operator.get(TreeIndexCode.Get_Immediate_Children, this.userId, filter);
	}

	/**
	 *  移动弟弟节点
	 * @param sParentID     父节点ID
	 * @param sequence      起始排序
	 * @param operatorType  节点类型
	 * @param after         true:向后移动  false:向前移动
	 * @throws ErrorMessage 
	 */
	private void moveLBrother(ArrayList<String> sql,String sParentID,Object sequence,
			String operatorType,boolean after) throws ErrorMessage{
		this.moveLBrother(sql, sParentID, sequence, operatorType, null, after);
	}
	
	/**
	 *  移动弟弟节点
	 * @param sParentID     父节点ID
	 * @param sequence      起始排序
	 * @param operatorType  节点类型          
	 * @param indexType     索引类型(模型索引树使用)
	 * @param after         true:向后移动  false:向前移动
	 * @throws ErrorMessage 
	 */
	protected void moveLBrother(ArrayList<String> sql,String sParentID,Object sequence,
			String operatorType,String indexType,
			boolean after) throws ErrorMessage{
		String sOrder;
		if(after){
			sOrder = this.fields.getNodeSequence()+"+1"; //向后移动
		}else{
			sOrder = this.fields.getNodeSequence()+"-1"; //向前移动
		}
		Update update=new Update(this.tableName);
		update.putFieldIgnoreNull(this.fields.getNodeSequence(), sOrder);
		StringBuilder sp=new StringBuilder();
		sp.append(this.fields.getNodeParent());
		sp.append("='");
		sp.append(sParentID);
		sp.append("'");
		sp.append(" and ");
		sp.append(this.fields.getNodeSequence());
		sp.append(">");
		sp.append(sequence);
		if(operatorType!=null){
			sp.append(" and ");
			sp.append(this.fields.getOperatorType());
			sp.append("='");
			sp.append(operatorType);
			sp.append("'");
		}
		if(indexType!=null){
			sp.append(" and ");
			sp.append(this.fields.getNodeType());
			sp.append("='");
			sp.append(operatorType);
			sp.append("'");
		}
		update.setWhere(sp.toString()); 
		sql.add(update.getSimpleSql());
	}

	/**
	 *  根据节点类型生成排序号<BR>
	 *  1 主题：父亲的子主题个数+1 <BR>
	 *   2 叶子节点类型：父亲的叶子类型子节点个数+5000 <BR>
	 * @throws ErrorMessage 
	 */
	protected int orderNumByOperatorType(String parentId, String nodeType,
			String operatorType) throws ErrorMessage {
		int siblingNumb = getSimilarSibling(parentId, nodeType, operatorType);
		//根据节点类型返回当前节点的排序号
		return getOrder(operatorType, 
				siblingNumb+1  //在兄弟中的顺序为兄弟个数加1
				);
	}

	/**
	 *  根据在同类节点中的顺序生成节点的排序号
	 * @param operatorType 节点类型
	 * @param sequence     顺序
	 * @return  返回:如果是叶子节点,返回顺序号+5000 ,如果是非叶子节点返回顺序号
	 */
	protected int getOrder(String operatorType,
			int sequence){
		//根据节点类型返回当前节点的排序号
		if(operatorType.equals(TreeParam.Index_Tree_Node_Type.OTHER.toString())){
			return sequence+Non_Theme_Start_Order;
		}else if(operatorType.equals(TreeParam.Index_Tree_Node_Type.CUSTOM.toString())){
			return sequence+Custom_Node_Order;
		}else{
			return sequence;
		}
	}
	
	/**
	 * @return 指定类型的儿子个数
	 * @throws ErrorMessage 
	 */
	protected int getSimilarSibling(String parentId, String nodeType, String operatorType)
	throws ErrorMessage {
		//获取指定类型的兄弟
		OperatorResult childs = getSibling(parentId, nodeType, operatorType);
		//获取指定类型兄弟个数
		int siblingNumb;
		if(TOOLS.exist(childs)){
			siblingNumb = childs.size();
		}else{
			siblingNumb = 0;
		}
		return siblingNumb;
	}

	/**
	 *  获取指定节点的最大儿子
	 * @param parentId 节点ID
	 * @param nodeType 节点索引类型
	 * @return 指定节点的最大儿子
	 * @throws ErrorMessage 
	 */
	protected String greatestChild(String parentId, String nodeType) throws ErrorMessage {
		String gChild = null;
		OperatorResult siblings = getSibling(parentId, nodeType, null);
		if(TOOLS.exist(siblings)){
			SqlResult sr = siblings.getSelectResult();
			gChild = sr.get(0, this.fields.getNodeId());//最大儿子
		}
		return gChild;
	}
	
	/**
	 *  获取指定节点的最小儿子
	 * @param parentId 节点ID
	 * @param nodeType 节点索引类型
	 * @return 指定节点的最小儿子
	 * @throws ErrorMessage 
	 */
	protected String littleChild(String parentId, String nodeType) throws ErrorMessage {
		String littleChild = null;
		OperatorResult siblings = getSibling(parentId, nodeType, null);
		if(TOOLS.exist(siblings)){
			SqlResult sr = siblings.getSelectResult();
			littleChild = sr.get(sr.size()-1, this.fields.getNodeId());//最小儿子
		}
		return littleChild;
	}
}
